package com.ham.mud.state;

import com.ham.mud.Colors;
import com.ham.mud.Runner;
import com.ham.mud.ServerConnection;
import com.ham.mud.characters.Experience;
import com.ham.mud.characters.player.Player;
import com.ham.mud.characters.player.PlayerService;
import com.ham.mud.classes.MudClass;
import com.ham.mud.classes.MudClassService;
import com.ham.mud.commands.LookCommand;
import com.ham.mud.races.Race;
import com.ham.mud.races.RaceService;
import com.sun.xml.internal.ws.util.StringUtils;

import java.io.IOException;
import java.util.Random;

/**
 * Created by hlucas on Jun 16, 2011 at 12:16:51 PM
 */
public class LoginState extends ConnectionState {
    private static final Random rand = new Random();

    private enum Stage {
        gettingUsername, gettingPassword, askingNewCharacter, pickingClass, pickingRace, pickingPassword
    }

    private Stage currentStage;

    Player player;
    MudClass mudClass;
    Race race;
    String username;
    String password;

    public LoginState(ServerConnection connection) {
        super(connection);
        promptForUsername();
    }

    @Override
    public void processInput(String line) {
        if(currentStage == Stage.gettingUsername) {
            processUsername(line);
        } else if(currentStage == Stage.askingNewCharacter) {
            processNewCharacter(line);
        } else if(currentStage == Stage.pickingClass) {
            processPickingClass(line);
        } else if(currentStage == Stage.pickingRace){
            processPickingRace(line);
        } else if(currentStage == Stage.pickingPassword){
            processPickingPassword(line);
        } else if(currentStage == Stage.gettingPassword) {
            processPassword(line);
        }
    }

    private void processUsername(String line) {
        currentStage = Stage.askingNewCharacter;
        username = line;

        boolean playerExists = PlayerService.exists(username);
        if(playerExists) {
            promptForPassword();
        } else {
            promptForNewCharacter();
        }
    }

    private void processNewCharacter(String line) {
        currentStage = Stage.pickingClass;

        if(line.toLowerCase().startsWith("y")) {
            connection.println("New character." + Colors.NEW_LINE);
            promptForRace();
        } else {
            connection.println("Too bad.");
            promptForUsername();
        }
    }

    private void processPickingClass(String line) {
        line = line.toLowerCase();
        MudClass mudClass = MudClassService.getClass(line);
        if(mudClass == null) {
            connection.println(line + " is not a valid option. Try again.");
            promptForClass();
            return;
        }

        connection.println(StringUtils.capitalize(mudClass.getName()) + "! An excellent choice." + Colors.NEW_LINE);
        this.mudClass = mudClass;

        promptForNewPassword();
    }

    private void processPickingRace(String line) {
        Race race = RaceService.getRace(line);
        if(race == null) {
            connection.println(line + " is not a valid option. Try again.");
            promptForRace();
            return;
        }

        connection.println("Ah yes, a vicious " + race.getName() + " should be a great fit." + Colors.NEW_LINE);
        this.race = race;

        promptForClass();
    }

    private void processPickingPassword(String line) {
        if(line == null || line.equals("")) {
            connection.println("That is not a valid password.");
            promptForNewPassword();
            return;
        }

        this.password = line;
        createNewPlayer();

        this.currentStage = Stage.gettingPassword;
    }

    private void processPassword(String line) {
        currentStage = null;
        if(line == null || line.equals("")) promptForPassword();

        if(PlayerService.checkPassword(username, line)) {
            loginUser(username);
        } else {
            connection.println("That is not the correct password.");
            promptForPassword();
        }
    }

    private void createNewPlayer() {
        player = new Player(username, password, "town", 0, 0);
        player.setMudClass(mudClass);
        player.setRace(race);
        player.setExperience(new Experience(0));
        PlayerService.save(player);
        connection.setPlayer(player);

        connection.println("Your password is '" + this.password + "' for now.");
        connection.changeState(new PlayingState(connection));
        printAscii();
        new LookCommand().execute(connection);
        Runner.STATIC_INSTANCE.addConnection(connection);
    }

    private void loginUser(String username) {
        try {
            player = PlayerService.load(username);
        } catch (IOException e) {
            e.printStackTrace();
        }

        connection.setPlayer(player);
        connection.changeState(new PlayingState(connection));
        printAscii();
        new LookCommand().execute(connection);
        Runner.STATIC_INSTANCE.addConnection(connection);
    }

    private void promptForUsername() {
        connection.print("Username: ");
        currentStage = Stage.gettingUsername;
    }

    private void promptForRace() {
        RaceService.showRaces(connection);
        connection.print("Race: ");
        currentStage = Stage.pickingRace;
    }

    private void promptForClass() {
        MudClassService.showClasses(connection);
        connection.print("Class: ");
        currentStage = Stage.pickingClass;
    }

    private void promptForNewCharacter() {
        connection.print(username + " does not exist. Create new character? y/n: ");
        currentStage = Stage.askingNewCharacter;
    }

    private void promptForNewPassword() {
        connection.println("Alright, " + username + ", what would you like your password to be?");
        connection.print("Password: ");
        currentStage = Stage.pickingPassword;
    }

    private void promptForPassword() {
        connection.print("Password: ");
        currentStage = Stage.gettingPassword;
    }

    private void printAscii() {
        Colors.printASCII("intro" + rand.nextInt(3), connection);
    }

    @Override
    public void tick() {
    }
}
